Skip to content

Session: session-c interface#17347

Open
hongzhi-gao wants to merge 5 commits intoapache:masterfrom
hongzhi-gao:feature/session-c-interface
Open

Session: session-c interface#17347
hongzhi-gao wants to merge 5 commits intoapache:masterfrom
hongzhi-gao:feature/session-c-interface

Conversation

@hongzhi-gao
Copy link
Copy Markdown
Contributor

@hongzhi-gao hongzhi-gao commented Mar 24, 2026

Description

What

Adds a C API (SessionC.h / SessionC.cpp) around the existing C++ Session / TableSession, for C/FFI callers without exposing C++ types.

Design

Opaque handles (CSession, CTableSession, CTablet, CSessionDataSet, CRowRecord); public symbols prefixed with ts_*.
TsStatus return codes + thread-local last error via ts_get_last_error().
Thin wrappers: convert C args → C++ types, map exceptions to status codes; reuse existing client logic (no duplicate Thrift layer).

Scope

Tree + table model: connect, metadata, inserts (record/tablet), queries, result iteration, deletes—aligned with current Session behavior.

This PR has:

self-reviewed
tests added or updated

Key files

client-cpp/src/main/SessionC.h, SessionC.cpp
client-cpp/src/test/main_c*.cpp, sessionC*IT.cpp

@hongzhi-gao hongzhi-gao changed the title session c Session: session-c interface Mar 24, 2026
Comment on lines +222 to +232
clearError();
try {
auto* cs = new CSession_();
cs->cpp = std::make_shared<Session>(
std::string(host), rpcPort,
std::string(username), std::string(password));
return cs;
} catch (const std::exception& e) {
handleException(e);
return nullptr;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will cs be freed when an exception occurs?
The same below.

Comment on lines +349 to +351
void ts_table_session_destroy(CTableSession* session) {
delete session;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check if it is nullptr?

Comment on lines +482 to +484
std::map<std::string, std::string> props = propsCount > 0 ? toStringMap(propsCount, propKeys, propValues) : std::map<std::string, std::string>();
std::map<std::string, std::string> tags = tagsCount > 0 ? toStringMap(tagsCount, tagKeys, tagValues) : std::map<std::string, std::string>();
std::map<std::string, std::string> attrs = attrsCount > 0 ? toStringMap(attrsCount, attrKeys, attrValues) : std::map<std::string, std::string>();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this result in unnecessary copying?

Comment on lines +1239 to +1246
bool ts_dataset_has_next(CSessionDataSet* dataSet) {
if (!dataSet || !dataSet->cpp) return false;
try {
return dataSet->cpp->hasNext();
} catch (...) {
return false;
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

global error?
The same below.

Comment on lines +1306 to +1323
bool ts_row_record_is_null(CRowRecord* record, int index) {
if (!record || !record->cpp) return true;
if (index < 0 || index >= (int)record->cpp->fields.size()) return true;
const Field& f = record->cpp->fields[index];
switch (f.dataType) {
case TSDataType::BOOLEAN: return !f.boolV.is_initialized();
case TSDataType::INT32: return !f.intV.is_initialized();
case TSDataType::INT64:
case TSDataType::TIMESTAMP: return !f.longV.is_initialized();
case TSDataType::FLOAT: return !f.floatV.is_initialized();
case TSDataType::DOUBLE: return !f.doubleV.is_initialized();
case TSDataType::TEXT:
case TSDataType::STRING:
case TSDataType::BLOB: return !f.stringV.is_initialized();
case TSDataType::DATE: return !f.dateV.is_initialized();
default: return true;
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No such a method in Cpp?

Comment on lines +1374 to +1375
if (!record || !record->cpp) return TS_TYPE_TEXT;
if (index < 0 || index >= (int)record->cpp->fields.size()) return TS_TYPE_TEXT;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TS_TYPE_INVALID?

Comment on lines 32 to +43
void testCaseStarting(Catch::TestCaseInfo const &testInfo) override {
// Perform some setup before a test case is run
session->open(false);
if (!session) {
SessionBuilder builder;
session = builder.host("127.0.0.1")
->rpcPort(6667)
->username("root")
->password("root")
->useSSL(false)
->build();
} else {
session->open(false);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Session is not open in the first test?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants